home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 7: Programming / CDAT7.iso / Share / Codigo / hh / rsource.exe / Hexen Source / PO_MAN.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-22  |  34.3 KB  |  1,483 lines

  1.  
  2. //**************************************************************************
  3. //**
  4. //** PO_MAN.C : Heretic 2 : Raven Software, Corp.
  5. //**
  6. //** $RCSfile: po_man.c,v $
  7. //** $Revision: 1.22 $
  8. //** $Date: 95/09/28 18:20:56 $
  9. //** $Author: cjr $
  10. //**
  11. //**************************************************************************
  12.  
  13. // HEADER FILES ------------------------------------------------------------
  14.  
  15. #include "h2def.h"
  16. #include "p_local.h"
  17. #include "r_local.h"
  18.  
  19. // MACROS ------------------------------------------------------------------
  20.  
  21. #define PO_MAXPOLYSEGS 64
  22.  
  23. // TYPES -------------------------------------------------------------------
  24.  
  25. // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
  26.  
  27. boolean PO_MovePolyobj(int num, int x, int y);
  28. boolean PO_RotatePolyobj(int num, angle_t angle);
  29. void PO_Init(int lump);
  30.  
  31. // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
  32.  
  33. static polyobj_t *GetPolyobj(int polyNum);
  34. static int GetPolyobjMirror(int poly);
  35. static void ThrustMobj(mobj_t *mobj, seg_t *seg, polyobj_t *po);
  36. static void UpdateSegBBox(seg_t *seg);
  37. static void RotatePt(int an, fixed_t *x, fixed_t *y, fixed_t startSpotX,
  38.     fixed_t startSpotY);
  39. static void UnLinkPolyobj(polyobj_t *po);
  40. static void LinkPolyobj(polyobj_t *po);
  41. static boolean CheckMobjBlocking(seg_t *seg, polyobj_t *po);
  42. static void InitBlockMap(void);
  43. static void IterFindPolySegs(int x, int y, seg_t **segList);
  44. static void SpawnPolyobj(int index, int tag, boolean crush);
  45. static void TranslateToStartSpot(int tag, int originX, int originY);
  46.  
  47. // EXTERNAL DATA DECLARATIONS ----------------------------------------------
  48.  
  49. extern seg_t *segs;
  50.  
  51. // PUBLIC DATA DEFINITIONS -------------------------------------------------
  52.  
  53. polyblock_t **PolyBlockMap;
  54. polyobj_t *polyobjs; // list of all poly-objects on the level
  55. int po_NumPolyobjs;
  56.  
  57. // PRIVATE DATA DEFINITIONS ------------------------------------------------
  58.  
  59. static int PolySegCount;
  60. static fixed_t PolyStartX;
  61. static fixed_t PolyStartY;
  62.  
  63. // CODE --------------------------------------------------------------------
  64.  
  65. // ===== Polyobj Event Code =====
  66.  
  67. //==========================================================================
  68. //
  69. // T_RotatePoly
  70. //
  71. //==========================================================================
  72.  
  73. void T_RotatePoly(polyevent_t *pe)
  74. {
  75.     int absSpeed;
  76.     polyobj_t *poly;
  77.  
  78.     if(PO_RotatePolyobj(pe->polyobj, pe->speed))
  79.     {
  80.         absSpeed = abs(pe->speed);
  81.  
  82.         if(pe->dist == -1)
  83.         { // perpetual polyobj
  84.             return;
  85.         }
  86.         pe->dist -= absSpeed;
  87.         if(pe->dist <= 0)
  88.         {
  89.             poly = GetPolyobj(pe->polyobj);
  90.             if(poly->specialdata == pe)
  91.             {
  92.                 poly->specialdata = NULL;
  93.             }
  94.             SN_StopSequence((mobj_t *)&poly->startSpot);
  95.             P_PolyobjFinished(poly->tag);
  96.             P_RemoveThinker(&pe->thinker);
  97.         }
  98.         if(pe->dist < absSpeed)
  99.         {
  100.             pe->speed = pe->dist*(pe->speed < 0 ? -1 : 1);
  101.         }
  102.     }
  103. }
  104.  
  105. //==========================================================================
  106. //
  107. // EV_RotatePoly
  108. //
  109. //==========================================================================
  110.  
  111. boolean EV_RotatePoly(line_t *line, byte *args, int direction, boolean 
  112.     overRide)
  113. {
  114.     int mirror;
  115.     int polyNum;
  116.     polyevent_t *pe;
  117.     polyobj_t *poly;
  118.  
  119.     polyNum = args[0];
  120.     if(poly = GetPolyobj(polyNum))
  121.     {
  122.         if(poly->specialdata && !overRide)
  123.         { // poly is already moving
  124.             return false;
  125.         }
  126.     }
  127.     else
  128.     {
  129.         I_Error("EV_RotatePoly:  Invalid polyobj num: %d\n", polyNum);
  130.     }
  131.     pe = Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, 0);
  132.     P_AddThinker(&pe->thinker);
  133.     pe->thinker.function = T_RotatePoly;
  134.     pe->polyobj = polyNum;
  135.     if(args[2])
  136.     {
  137.         if(args[2] == 255)
  138.         {
  139.             pe->dist = -1;
  140.         }
  141.         else
  142.         {
  143.             pe->dist = args[2]*(ANGLE_90/64); // Angle
  144.         }
  145.     }
  146.     else
  147.     {
  148.         pe->dist = ANGLE_MAX-1;
  149.     }
  150.     pe->speed = (args[1]*direction*(ANGLE_90/64))>>3;
  151.     poly->specialdata = pe;
  152.     SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE+
  153.         poly->seqType);
  154.     
  155.     while(mirror = GetPolyobjMirror(polyNum))
  156.     {
  157.         poly = GetPolyobj(mirror);
  158.         if(poly && poly->specialdata && !overRide)
  159.         { // mirroring poly is already in motion
  160.             break;
  161.         }
  162.         pe = Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, 0);
  163.         P_AddThinker(&pe->thinker);
  164.         pe->thinker.function = T_RotatePoly;
  165.         poly->specialdata = pe;
  166.         pe->polyobj = mirror;
  167.         if(args[2])
  168.         {
  169.             if(args[2] == 255)
  170.             {
  171.                 pe->dist = -1;
  172.             }
  173.             else
  174.             {
  175.                 pe->dist = args[2]*(ANGLE_90/64); // Angle
  176.             }
  177.         }
  178.         else
  179.         {
  180.             pe->dist = ANGLE_MAX-1;
  181.         }
  182.         if(poly = GetPolyobj(polyNum))
  183.         {
  184.             poly->specialdata = pe;
  185.         }
  186.         else
  187.         {
  188.             I_Error("EV_RotatePoly:  Invalid polyobj num: %d\n", polyNum);
  189.         }
  190.         direction = -direction;
  191.         pe->speed = (args[1]*direction*(ANGLE_90/64))>>3;
  192.         polyNum = mirror;
  193.         SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE+
  194.             poly->seqType);
  195.     }
  196.     return true;
  197. }
  198.  
  199. //==========================================================================
  200. //
  201. // T_MovePoly
  202. //
  203. //==========================================================================
  204.  
  205. void T_MovePoly(polyevent_t *pe)
  206. {
  207.     int absSpeed;
  208.     polyobj_t *poly;
  209.  
  210.     if(PO_MovePolyobj(pe->polyobj, pe->xSpeed, pe->ySpeed))
  211.     {
  212.         absSpeed = abs(pe->speed);
  213.         pe->dist -= absSpeed;
  214.         if(pe->dist <= 0)
  215.         {
  216.             poly = GetPolyobj(pe->polyobj);
  217.             if(poly->specialdata == pe)
  218.             {
  219.                 poly->specialdata = NULL;
  220.             }
  221.             SN_StopSequence((mobj_t *)&poly->startSpot);
  222.             P_PolyobjFinished(poly->tag);
  223.             P_RemoveThinker(&pe->thinker);
  224.         }
  225.         if(pe->dist < absSpeed)
  226.         {
  227.             pe->speed = pe->dist*(pe->speed < 0 ? -1 : 1);
  228.             pe->xSpeed = FixedMul(pe->speed, finecosine[pe->angle]);
  229.             pe->ySpeed = FixedMul(pe->speed, finesine[pe->angle]);
  230.         }
  231.     }
  232. }
  233.  
  234. //==========================================================================
  235. //
  236. // EV_MovePoly
  237. //
  238. //==========================================================================
  239.  
  240. boolean EV_MovePoly(line_t *line, byte *args, boolean timesEight, boolean 
  241.     overRide)
  242. {
  243.     int mirror;
  244.     int polyNum;
  245.     polyevent_t *pe;
  246.     polyobj_t *poly;
  247.     angle_t an;
  248.  
  249.     polyNum = args[0];
  250.     if(poly = GetPolyobj(polyNum))
  251.     {
  252.         if(poly->specialdata && !overRide)
  253.         { // poly is already moving
  254.             return false;
  255.         }
  256.     }
  257.     else
  258.     {
  259.         I_Error("EV_MovePoly:  Invalid polyobj num: %d\n", polyNum);
  260.     }
  261.     pe = Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, 0);
  262.     P_AddThinker(&pe->thinker);
  263.     pe->thinker.function = T_MovePoly;
  264.     pe->polyobj = polyNum;
  265.     if(timesEight)
  266.     {
  267.         pe->dist = args[3]*8*FRACUNIT;
  268.     }
  269.     else
  270.     {
  271.         pe->dist = args[3]*FRACUNIT; // Distance
  272.     }
  273.     pe->speed = args[1]*(FRACUNIT/8);
  274.     poly->specialdata = pe;
  275.  
  276.     an = args[2]*(ANGLE_90/64);
  277.  
  278.     pe->angle = an>>ANGLETOFINESHIFT;
  279.     pe->xSpeed = FixedMul(pe->speed, finecosine[pe->angle]);
  280.     pe->ySpeed = FixedMul(pe->speed, finesine[pe->angle]);
  281.     SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE+
  282.         poly->seqType);
  283.  
  284.     while(mirror = GetPolyobjMirror(polyNum))
  285.     {
  286.         poly = GetPolyobj(mirror);
  287.         if(poly && poly->specialdata && !overRide)
  288.         { // mirroring poly is already in motion
  289.             break;
  290.         }
  291.         pe = Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, 0);
  292.         P_AddThinker(&pe->thinker);
  293.         pe->thinker.function = T_MovePoly;
  294.         pe->polyobj = mirror;
  295.         poly->specialdata = pe;
  296.         if(timesEight)
  297.         {
  298.             pe->dist = args[3]*8*FRACUNIT;
  299.         }
  300.         else
  301.         {
  302.             pe->dist = args[3]*FRACUNIT; // Distance
  303.         }
  304.         pe->speed = args[1]*(FRACUNIT/8);
  305.         an = an+ANGLE_180; // reverse the angle
  306.         pe->angle = an>>ANGLETOFINESHIFT;
  307.         pe->xSpeed = FixedMul(pe->speed, finecosine[pe->angle]);
  308.         pe->ySpeed = FixedMul(pe->speed, finesine[pe->angle]);
  309.         polyNum = mirror;
  310.         SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE+
  311.             poly->seqType);
  312.     }
  313.     return true;
  314. }
  315.  
  316. //==========================================================================
  317. //
  318. // T_PolyDoor
  319. //
  320. //==========================================================================
  321.  
  322. void T_PolyDoor(polydoor_t *pd)
  323. {
  324.     int absSpeed;
  325.     polyobj_t *poly;
  326.  
  327.     if(pd->tics)
  328.     {
  329.         if(!--pd->tics)
  330.         {
  331.             poly = GetPolyobj(pd->polyobj);
  332.             SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE+
  333.                 poly->seqType);
  334.         }
  335.         return;
  336.     }
  337.     switch(pd->type)
  338.     {
  339.         case PODOOR_SLIDE:
  340.             if(PO_MovePolyobj(pd->polyobj, pd->xSpeed, pd->ySpeed))
  341.             {
  342.                 absSpeed = abs(pd->speed);
  343.                 pd->dist -= absSpeed;
  344.                 if(pd->dist <= 0)
  345.                 {
  346.                     poly = GetPolyobj(pd->polyobj);
  347.                     SN_StopSequence((mobj_t *)&poly->startSpot);
  348.                     if(!pd->close)
  349.                     {
  350.                         pd->dist = pd->totalDist;
  351.                         pd->close = true;
  352.                         pd->tics = pd->waitTics;
  353.                         pd->direction = (ANGLE_MAX>>ANGLETOFINESHIFT)-
  354.                             pd->direction;
  355.                         pd->xSpeed = -pd->xSpeed;
  356.                         pd->ySpeed = -pd->ySpeed;                    
  357.                     }
  358.                     else
  359.                     {
  360.                         if(poly->specialdata == pd)
  361.                         {
  362.                             poly->specialdata = NULL;
  363.                         }
  364.                         P_PolyobjFinished(poly->tag);
  365.                         P_RemoveThinker(&pd->thinker);
  366.                     }
  367.                 }
  368.             }
  369.             else
  370.             {
  371.                 poly = GetPolyobj(pd->polyobj);
  372.                 if(poly->crush || !pd->close)
  373.                 { // continue moving if the poly is a crusher, or is opening
  374.                     return;
  375.                 }
  376.                 else
  377.                 { // open back up
  378.                     pd->dist = pd->totalDist-pd->dist;
  379.                     pd->direction = (ANGLE_MAX>>ANGLETOFINESHIFT)-
  380.                         pd->direction;
  381.                     pd->xSpeed = -pd->xSpeed;
  382.                     pd->ySpeed = -pd->ySpeed;
  383.                     pd->close = false;
  384.                     SN_StartSequence((mobj_t *)&poly->startSpot,
  385.                         SEQ_DOOR_STONE+poly->seqType);
  386.                 }
  387.             }
  388.             break;
  389.         case PODOOR_SWING:
  390.             if(PO_RotatePolyobj(pd->polyobj, pd->speed))
  391.             {
  392.                 absSpeed = abs(pd->speed);
  393.                 if(pd->dist == -1)
  394.                 { // perpetual polyobj
  395.                     return;
  396.                 }
  397.                 pd->dist -= absSpeed;
  398.                 if(pd->dist <= 0)
  399.                 {
  400.                     poly = GetPolyobj(pd->polyobj);
  401.                     SN_StopSequence((mobj_t *)&poly->startSpot);
  402.                     if(!pd->close)
  403.                     {
  404.                         pd->dist = pd->totalDist;
  405.                         pd->close = true;
  406.                         pd->tics = pd->waitTics;
  407.                         pd->speed = -pd->speed;
  408.                     }
  409.                     else
  410.                     {
  411.                         if(poly->specialdata == pd)
  412.                         {
  413.                             poly->specialdata = NULL;
  414.                         }
  415.                         P_PolyobjFinished(poly->tag);
  416.                         P_RemoveThinker(&pd->thinker);
  417.                     }
  418.                 }
  419.             }
  420.             else
  421.             {
  422.                 poly = GetPolyobj(pd->polyobj);
  423.                 if(poly->crush || !pd->close)
  424.                 { // continue moving if the poly is a crusher, or is opening
  425.                     return;
  426.                 }
  427.                 else
  428.                 { // open back up and rewait
  429.                     pd->dist = pd->totalDist-pd->dist;
  430.                     pd->speed = -pd->speed;
  431.                     pd->close = false;
  432.                     SN_StartSequence((mobj_t *)&poly->startSpot,
  433.                         SEQ_DOOR_STONE+poly->seqType);
  434.                 }
  435.             }            
  436.             break;
  437.         default:
  438.             break;
  439.     }
  440. }
  441.  
  442. //==========================================================================
  443. //
  444. // EV_OpenPolyDoor
  445. //
  446. //==========================================================================
  447.  
  448. boolean EV_OpenPolyDoor(line_t *line, byte *args, podoortype_t type)
  449. {
  450.     int mirror;
  451.     int polyNum;
  452.     polydoor_t *pd;
  453.     polyobj_t *poly;
  454.     angle_t an;
  455.  
  456.     polyNum = args[0];
  457.     if(poly = GetPolyobj(polyNum))
  458.     {
  459.         if(poly->specialdata)
  460.         { // poly is already moving
  461.             return false;
  462.         }
  463.     }
  464.     else
  465.     {
  466.         I_Error("EV_OpenPolyDoor:  Invalid polyobj num: %d\n", polyNum);
  467.     }
  468.     pd = Z_Malloc(sizeof(polydoor_t), PU_LEVSPEC, 0);
  469.     memset(pd, 0, sizeof(polydoor_t));
  470.     P_AddThinker(&pd->thinker);
  471.     pd->thinker.function = T_PolyDoor;
  472.     pd->type = type;
  473.     pd->polyobj = polyNum;
  474.     if(type == PODOOR_SLIDE)
  475.     {
  476.         pd->waitTics = args[4];
  477.         pd->speed = args[1]*(FRACUNIT/8);
  478.         pd->totalDist = args[3]*FRACUNIT; // Distance
  479.         pd->dist = pd->totalDist;
  480.         an = args[2]*(ANGLE_90/64);
  481.         pd->direction = an>>ANGLETOFINESHIFT;
  482.         pd->xSpeed = FixedMul(pd->speed, finecosine[pd->direction]);
  483.         pd->ySpeed = FixedMul(pd->speed, finesine[pd->direction]);
  484.         SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE+
  485.             poly->seqType);
  486.     }
  487.     else if(type == PODOOR_SWING)
  488.     {
  489.         pd->waitTics = args[3];
  490.         pd->direction = 1; // ADD:  PODOOR_SWINGL, PODOOR_SWINGR
  491.         pd->speed = (args[1]*pd->direction*(ANGLE_90/64))>>3;
  492.         pd->totalDist = args[2]*(ANGLE_90/64);
  493.         pd->dist = pd->totalDist;
  494.         SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE+
  495.             poly->seqType);
  496.     }
  497.  
  498.     poly->specialdata = pd;
  499.  
  500.     while(mirror = GetPolyobjMirror(polyNum))
  501.     {
  502.         poly = GetPolyobj(mirror);
  503.         if(poly && poly->specialdata)
  504.         { // mirroring poly is already in motion
  505.             break;
  506.         }
  507.         pd = Z_Malloc(sizeof(polydoor_t), PU_LEVSPEC, 0);
  508.         memset(pd, 0, sizeof(polydoor_t));
  509.         P_AddThinker(&pd->thinker);
  510.         pd->thinker.function = T_PolyDoor;
  511.         pd->polyobj = mirror;
  512.         pd->type = type;
  513.         poly->specialdata = pd;
  514.         if(type == PODOOR_SLIDE)
  515.         {
  516.             pd->waitTics = args[4];
  517.             pd->speed = args[1]*(FRACUNIT/8);
  518.             pd->totalDist = args[3]*FRACUNIT; // Distance
  519.             pd->dist = pd->totalDist;
  520.             an = an+ANGLE_180; // reverse the angle
  521.             pd->direction = an>>ANGLETOFINESHIFT;
  522.             pd->xSpeed = FixedMul(pd->speed, finecosine[pd->direction]);
  523.             pd->ySpeed = FixedMul(pd->speed, finesine[pd->direction]);
  524.             SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE+
  525.                 poly->seqType);
  526.         }
  527.         else if(type == PODOOR_SWING)
  528.         {
  529.             pd->waitTics = args[3];
  530.             pd->direction = -1; // ADD:  same as above
  531.             pd->speed = (args[1]*pd->direction*(ANGLE_90/64))>>3;
  532.             pd->totalDist = args[2]*(ANGLE_90/64);
  533.             pd->dist = pd->totalDist;
  534.             SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE+
  535.                 poly->seqType);
  536.         }
  537.         polyNum = mirror;
  538.     }
  539.     return true;
  540. }
  541.     
  542. // ===== Higher Level Poly Interface code =====
  543.  
  544. //==========================================================================
  545. //
  546. // GetPolyobj
  547. //
  548. //==========================================================================
  549.  
  550. static polyobj_t *GetPolyobj(int polyNum)
  551. {
  552.     int i;
  553.  
  554.     for(i = 0; i < po_NumPolyobjs; i++)
  555.     {
  556.         if(polyobjs[i].tag == polyNum)
  557.         {
  558.             return &polyobjs[i];
  559.         }
  560.     }
  561.     return NULL;
  562. }
  563.  
  564. //==========================================================================
  565. //
  566. // GetPolyobjMirror
  567. //
  568. //==========================================================================
  569.  
  570. static int GetPolyobjMirror(int poly)
  571. {
  572.     int i;
  573.  
  574.     for(i = 0; i < po_NumPolyobjs; i++)
  575.     {
  576.         if(polyobjs[i].tag == poly)
  577.         {
  578.             return((*polyobjs[i].segs)->linedef->arg2);
  579.         }
  580.     }
  581.     return 0;
  582. }
  583.  
  584. //==========================================================================
  585. //
  586. // ThrustMobj
  587. //
  588. //==========================================================================
  589.  
  590. static void ThrustMobj(mobj_t *mobj, seg_t *seg, polyobj_t *po)
  591. {
  592.     int thrustAngle;
  593.     int thrustX;
  594.     int thrustY;
  595.     polyevent_t *pe;
  596.  
  597.     int force;
  598.  
  599.     if(!(mobj->flags&MF_SHOOTABLE) && !mobj->player)
  600.     {
  601.         return;
  602.     }
  603.     thrustAngle = (seg->angle-ANGLE_90)>>ANGLETOFINESHIFT;
  604.  
  605.     pe = po->specialdata;
  606.     if(pe)
  607.     {
  608.         if(pe->thinker.function == T_RotatePoly)
  609.         {
  610.             force = pe->speed>>8;
  611.         }
  612.         else
  613.         {
  614.             force = pe->speed>>3;
  615.         }
  616.         if(force < FRACUNIT)
  617.         {
  618.             force = FRACUNIT;
  619.         }
  620.         else if(force > 4*FRACUNIT)
  621.         {
  622.             force = 4*FRACUNIT;
  623.         }
  624.     }
  625.     else
  626.     {
  627.         force = FRACUNIT;
  628.     }
  629.  
  630.     thrustX = FixedMul(force, finecosine[thrustAngle]);
  631.     thrustY = FixedMul(force, finesine[thrustAngle]);
  632.     mobj->momx += thrustX;
  633.     mobj->momy += thrustY;
  634.     if(po->crush)
  635.     {
  636.         if(!P_CheckPosition(mobj, mobj->x+thrustX, mobj->y+thrustY))
  637.         {
  638.             P_DamageMobj(mobj, NULL, NULL, 3);
  639.         }
  640.     }
  641. }
  642.  
  643. //==========================================================================
  644. //
  645. // UpdateSegBBox
  646. //
  647. //==========================================================================
  648.  
  649. static void UpdateSegBBox(seg_t *seg)
  650. {
  651.     line_t *line;
  652.  
  653.     line = seg->linedef;
  654.  
  655.     if(seg->v1->x < seg->v2->x)
  656.     {
  657.         line->bbox[BOXLEFT] = seg->v1->x;
  658.         line->bbox[BOXRIGHT] = seg->v2->x;
  659.     }
  660.     else
  661.     {
  662.         line->bbox[BOXLEFT] = seg->v2->x;
  663.         line->bbox[BOXRIGHT] = seg->v1->x;
  664.     }
  665.     if(seg->v1->y < seg->v2->y)
  666.     {
  667.         line->bbox[BOXBOTTOM] = seg->v1->y;
  668.         line->bbox[BOXTOP] = seg->v2->y;
  669.     }
  670.     else
  671.     {
  672.         line->bbox[BOXBOTTOM] = seg->v2->y;
  673.         line->bbox[BOXTOP] = seg->v1->y;
  674.     }
  675.  
  676.     // Update the line's slopetype
  677.     line->dx = line->v2->x - line->v1->x;
  678.     line->dy = line->v2->y - line->v1->y;
  679.     if(!line->dx)
  680.     {
  681.         line->slopetype = ST_VERTICAL;
  682.     }
  683.     else if(!line->dy)
  684.     {
  685.         line->slopetype = ST_HORIZONTAL;
  686.     }
  687.     else
  688.     {
  689.         if(FixedDiv(line->dy, line->dx) > 0)
  690.         {
  691.             line->slopetype = ST_POSITIVE;
  692.         }
  693.         else
  694.         {
  695.             line->slopetype = ST_NEGATIVE;
  696.         }
  697.     }
  698. }
  699.  
  700. //==========================================================================
  701. //
  702. // PO_MovePolyobj
  703. //
  704. //==========================================================================
  705.  
  706. boolean PO_MovePolyobj(int num, int x, int y)
  707. {
  708.     int count;
  709.     seg_t **segList;
  710.     seg_t **veryTempSeg;
  711.     polyobj_t *po;
  712.     vertex_t *prevPts;
  713.     boolean blocked;
  714.  
  715.     if(!(po = GetPolyobj(num)))
  716.     {
  717.         I_Error("PO_MovePolyobj:  Invalid polyobj number: %d\n", num);
  718.     }
  719.  
  720.     UnLinkPolyobj(po);
  721.  
  722.     segList = po->segs;
  723.     prevPts = po->prevPts;
  724.     blocked = false;
  725.  
  726.     validcount++;
  727.     for(count = po->numsegs; count; count--, segList++, prevPts++)
  728.     {
  729.         if((*segList)->linedef->validcount != validcount)
  730.         {
  731.             (*segList)->linedef->bbox[BOXTOP] += y;
  732.             (*segList)->linedef->bbox[BOXBOTTOM] += y;
  733.             (*segList)->linedef->bbox[BOXLEFT] += x;
  734.             (*segList)->linedef->bbox[BOXRIGHT] += x;
  735.             (*segList)->linedef->validcount = validcount;
  736.         }
  737.         for(veryTempSeg = po->segs; veryTempSeg != segList;
  738.             veryTempSeg++)
  739.         {
  740.             if((*veryTempSeg)->v1 == (*segList)->v1)
  741.             {
  742.                 break;
  743.             }
  744.         }
  745.         if(veryTempSeg == segList)
  746.         {
  747.             (*segList)->v1->x += x;
  748.             (*segList)->v1->y += y;
  749.         }
  750.         (*prevPts).x += x; // previous points are unique for each seg
  751.         (*prevPts).y += y;
  752.     }
  753.     segList = po->segs;
  754.     for(count = po->numsegs; count; count--, segList++)
  755.     {
  756.         if(CheckMobjBlocking(*segList, po))
  757.         {
  758.             blocked = true;
  759.         }
  760.     }
  761.     if(blocked)
  762.     {
  763.         count = po->numsegs;
  764.         segList = po->segs;
  765.         prevPts = po->prevPts;
  766.         validcount++;
  767.         while(count--)
  768.         {
  769.             if((*segList)->linedef->validcount != validcount)
  770.             {
  771.                 (*segList)->linedef->bbox[BOXTOP] -= y;
  772.                 (*segList)->linedef->bbox[BOXBOTTOM] -= y;
  773.                 (*segList)->linedef->bbox[BOXLEFT] -= x;
  774.                 (*segList)->linedef->bbox[BOXRIGHT] -= x;
  775.                 (*segList)->linedef->validcount = validcount;
  776.             }
  777.             for(veryTempSeg = po->segs; veryTempSeg != segList;
  778.                 veryTempSeg++)
  779.             {
  780.                 if((*veryTempSeg)->v1 == (*segList)->v1)
  781.                 {
  782.                     break;
  783.                 }
  784.             }
  785.             if(veryTempSeg == segList)
  786.             {
  787.                 (*segList)->v1->x -= x;
  788.                 (*segList)->v1->y -= y;
  789.             }
  790.             (*prevPts).x -= x;
  791.             (*prevPts).y -= y;
  792.             segList++;
  793.             prevPts++;
  794.         }
  795.         LinkPolyobj(po);
  796.         return false;
  797.     }
  798.     po->startSpot.x += x;
  799.     po->startSpot.y += y;
  800.     LinkPolyobj(po);
  801.     return true;
  802. }
  803.  
  804. //==========================================================================
  805. //
  806. // RotatePt
  807. //
  808. //==========================================================================
  809.  
  810. static void RotatePt(int an, fixed_t *x, fixed_t *y, fixed_t startSpotX, fixed_t startSpotY)
  811. {
  812.     fixed_t trx, try;
  813.     fixed_t gxt, gyt;
  814.  
  815.     trx = *x;
  816.     try = *y;
  817.  
  818.     gxt = FixedMul(trx, finecosine[an]);
  819.     gyt = FixedMul(try, finesine[an]);
  820.     *x = (gxt-gyt)+startSpotX;
  821.  
  822.     gxt = FixedMul(trx, finesine[an]);
  823.     gyt = FixedMul(try, finecosine[an]);
  824.     *y = (gyt+gxt)+startSpotY;
  825. }
  826.  
  827. //==========================================================================
  828. //
  829. // PO_RotatePolyobj
  830. //
  831. //==========================================================================
  832.  
  833. boolean PO_RotatePolyobj(int num, angle_t angle)
  834. {
  835.     int count;
  836.     seg_t **segList;
  837.     vertex_t *originalPts;
  838.     vertex_t *prevPts;
  839.     int an;
  840.     polyobj_t *po;
  841.     boolean blocked;
  842.  
  843.     if(!(po = GetPolyobj(num)))
  844.     {
  845.         I_Error("PO_RotatePolyobj:  Invalid polyobj number: %d\n", num);
  846.     }
  847.     an = (po->angle+angle)>>ANGLETOFINESHIFT;
  848.  
  849.     UnLinkPolyobj(po);
  850.  
  851.     segList = po->segs;
  852.     originalPts = po->originalPts;
  853.     prevPts = po->prevPts;
  854.  
  855.     for(count = po->numsegs; count; count--, segList++, originalPts++,
  856.         prevPts++)
  857.     {
  858.         prevPts->x = (*segList)->v1->x;
  859.         prevPts->y = (*segList)->v1->y;
  860.         (*segList)->v1->x = originalPts->x;
  861.         (*segList)->v1->y = originalPts->y;
  862.         RotatePt(an, &(*segList)->v1->x, &(*segList)->v1->y, po->startSpot.x,
  863.             po->startSpot.y);
  864.     }
  865.     segList = po->segs;
  866.     blocked = false;
  867.     validcount++;
  868.     for(count = po->numsegs; count; count--, segList++)
  869.     {
  870.         if(CheckMobjBlocking(*segList, po))
  871.         {
  872.             blocked = true;
  873.         }
  874.         if((*segList)->linedef->validcount != validcount)
  875.         {
  876.             UpdateSegBBox(*segList);
  877.             (*segList)->linedef->validcount = validcount;
  878.         }
  879.         (*segList)->angle += angle;
  880.     }
  881.     if(blocked)
  882.     {
  883.         segList = po->segs;
  884.         prevPts = po->prevPts;
  885.         for(count = po->numsegs; count; count--, segList++, prevPts++)
  886.         {
  887.             (*segList)->v1->x = prevPts->x;
  888.             (*segList)->v1->y = prevPts->y;
  889.         }
  890.         segList = po->segs;
  891.         validcount++;
  892.         for(count = po->numsegs; count; count--, segList++, prevPts++)
  893.         {
  894.             if((*segList)->linedef->validcount != validcount)
  895.             {
  896.                 UpdateSegBBox(*segList);
  897.                 (*segList)->linedef->validcount = validcount;
  898.             }
  899.             (*segList)->angle -= angle;
  900.         }
  901.         LinkPolyobj(po);
  902.         return false;
  903.     }
  904.     po->angle += angle;
  905.     LinkPolyobj(po);
  906.     return true;
  907. }
  908.  
  909. //==========================================================================
  910. //
  911. // UnLinkPolyobj
  912. //
  913. //==========================================================================
  914.  
  915. static void UnLinkPolyobj(polyobj_t *po)
  916. {
  917.     polyblock_t *link;
  918.     int i, j;
  919.     int index;
  920.  
  921.     // remove the polyobj from each blockmap section
  922.     for(j = po->bbox[BOXBOTTOM]; j <= po->bbox[BOXTOP]; j++)
  923.     {
  924.         index = j*bmapwidth;
  925.         for(i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++)
  926.         {
  927.             if(i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight)
  928.             {
  929.                 link = PolyBlockMap[index+i];
  930.                 while(link != NULL && link->polyobj != po)
  931.                 {
  932.                     link = link->next;
  933.                 }
  934.                 if(link == NULL)
  935.                 { // polyobj not located in the link cell
  936.                     continue;
  937.                 }
  938.                 link->polyobj = NULL;
  939.             }
  940.         }
  941.     }
  942. }
  943.  
  944. //==========================================================================
  945. //
  946. // LinkPolyobj
  947. //
  948. //==========================================================================
  949.  
  950. static void LinkPolyobj(polyobj_t *po)
  951. {
  952.     int leftX, rightX;
  953.     int topY, bottomY;
  954.     seg_t **tempSeg;
  955.     polyblock_t **link;
  956.     polyblock_t *tempLink;
  957.     int i, j;
  958.  
  959.     // calculate the polyobj bbox
  960.     tempSeg = po->segs;
  961.     rightX = leftX = (*tempSeg)->v1->x;
  962.     topY = bottomY = (*tempSeg)->v1->y;
  963.  
  964.     for(i = 0; i < po->numsegs; i++, tempSeg++)
  965.     {
  966.         if((*tempSeg)->v1->x > rightX)
  967.         {
  968.             rightX = (*tempSeg)->v1->x;
  969.         }
  970.         if((*tempSeg)->v1->x < leftX)
  971.         {
  972.             leftX = (*tempSeg)->v1->x;
  973.         }
  974.         if((*tempSeg)->v1->y > topY)
  975.         {
  976.             topY = (*tempSeg)->v1->y;
  977.         }
  978.         if((*tempSeg)->v1->y < bottomY)
  979.         {
  980.             bottomY = (*tempSeg)->v1->y;
  981.         }
  982.     }
  983.     po->bbox[BOXRIGHT] = (rightX-bmaporgx)>>MAPBLOCKSHIFT;
  984.     po->bbox[BOXLEFT] = (leftX-bmaporgx)>>MAPBLOCKSHIFT;
  985.     po->bbox[BOXTOP] = (topY-bmaporgy)>>MAPBLOCKSHIFT;
  986.     po->bbox[BOXBOTTOM] = (bottomY-bmaporgy)>>MAPBLOCKSHIFT;
  987.     // add the polyobj to each blockmap section
  988.     for(j = po->bbox[BOXBOTTOM]*bmapwidth; j <= po->bbox[BOXTOP]*bmapwidth;
  989.         j += bmapwidth)
  990.     {
  991.         for(i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++)
  992.         {
  993.             if(i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight*bmapwidth)
  994.             {
  995.                 link = &PolyBlockMap[j+i];
  996.                 if(!(*link))
  997.                 { // Create a new link at the current block cell
  998.                     *link = Z_Malloc(sizeof(polyblock_t), PU_LEVEL, 0);
  999.                     (*link)->next = NULL;
  1000.                     (*link)->prev = NULL;
  1001.                     (*link)->polyobj = po;
  1002.                     continue;
  1003.                 }
  1004.                 else
  1005.                 {
  1006.                     tempLink = *link;
  1007.                     while(tempLink->next != NULL && tempLink->polyobj != NULL)
  1008.                     {
  1009.                         tempLink = tempLink->next;
  1010.                     }
  1011.                 }
  1012.                 if(tempLink->polyobj == NULL)
  1013.                 {
  1014.                     tempLink->polyobj = po;
  1015.                     continue;
  1016.                 }
  1017.                 else
  1018.                 {
  1019.                     tempLink->next = Z_Malloc(sizeof(polyblock_t), 
  1020.                         PU_LEVEL, 0);
  1021.                     tempLink->next->next = NULL;
  1022.                     tempLink->next->prev = tempLink;
  1023.                     tempLink->next->polyobj = po;
  1024.                 }
  1025.             }
  1026.             // else, don't link the polyobj, since it's off the map
  1027.         }
  1028.     }
  1029. }
  1030.  
  1031. //==========================================================================
  1032. //
  1033. // CheckMobjBlocking
  1034. //
  1035. //==========================================================================
  1036.  
  1037. static boolean CheckMobjBlocking(seg_t *seg, polyobj_t *po)
  1038. {
  1039.     mobj_t *mobj;
  1040.     int i, j;
  1041.     int left, right, top, bottom;
  1042.     int tmbbox[4];
  1043.     line_t *ld;
  1044.     boolean blocked;
  1045.  
  1046.     ld = seg->linedef;
  1047.  
  1048.     top = (ld->bbox[BOXTOP]-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT;
  1049.     bottom = (ld->bbox[BOXBOTTOM]-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT;
  1050.     left = (ld->bbox[BOXLEFT]-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT;
  1051.     right = (ld->bbox[BOXRIGHT]-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT;
  1052.  
  1053.     blocked = false;
  1054.  
  1055.     bottom = bottom < 0 ? 0 : bottom;
  1056.     bottom = bottom >= bmapheight ? bmapheight-1 : bottom;
  1057.     top = top < 0 ? 0 : top;
  1058.     top = top >= bmapheight  ? bmapheight-1 : top;
  1059.     left = left < 0 ? 0 : left;
  1060.     left = left >= bmapwidth ? bmapwidth-1 : left;
  1061.     right = right < 0 ? 0 : right;
  1062.     right = right >= bmapwidth ?  bmapwidth-1 : right;
  1063.  
  1064.     for(j = bottom*bmapwidth; j <= top*bmapwidth; j += bmapwidth)
  1065.     {
  1066.         for(i = left; i <= right; i++)
  1067.         {
  1068.             for(mobj = blocklinks[j+i]; mobj; mobj = mobj->bnext)
  1069.             {
  1070.                 if(mobj->flags&MF_SOLID || mobj->player)
  1071.                 {
  1072.                     tmbbox[BOXTOP] = mobj->y+mobj->radius;
  1073.                     tmbbox[BOXBOTTOM] = mobj->y-mobj->radius;
  1074.                     tmbbox[BOXLEFT] = mobj->x-mobj->radius;
  1075.                     tmbbox[BOXRIGHT] = mobj->x+mobj->radius;
  1076.  
  1077.                     if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
  1078.                         ||      tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
  1079.                         ||      tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
  1080.                         ||      tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
  1081.                     {
  1082.                         continue;
  1083.                     }
  1084.                     if(P_BoxOnLineSide(tmbbox, ld) != -1)
  1085.                     {
  1086.                         continue;
  1087.                     }
  1088.                     ThrustMobj(mobj, seg, po);
  1089.                     blocked = true;
  1090.                 }
  1091.             }
  1092.         }
  1093.     }
  1094.     return blocked;
  1095. }
  1096.  
  1097. //==========================================================================
  1098. //
  1099. // InitBlockMap
  1100. //
  1101. //==========================================================================
  1102.  
  1103. static void InitBlockMap(void)
  1104. {
  1105.     int i;
  1106.  
  1107.     int j;
  1108.     seg_t **segList;
  1109.     int area;
  1110.     int leftX, rightX;
  1111.     int topY, bottomY;
  1112.  
  1113.     PolyBlockMap = Z_Malloc(bmapwidth*bmapheight*sizeof(polyblock_t *),
  1114.         PU_LEVEL, 0);
  1115.     memset(PolyBlockMap, 0, bmapwidth*bmapheight*sizeof(polyblock_t *));
  1116.  
  1117.     for(i = 0; i < po_NumPolyobjs; i++)
  1118.     {
  1119.         LinkPolyobj(&polyobjs[i]);
  1120.  
  1121.         // calculate a rough area
  1122.         // right now, working like shit...gotta fix this...
  1123.         segList = polyobjs[i].segs;
  1124.         leftX = rightX = (*segList)->v1->x;
  1125.         topY = bottomY = (*segList)->v1->y;
  1126.         for(j = 0; j < polyobjs[i].numsegs; j++, segList++)
  1127.         {
  1128.             if((*segList)->v1->x < leftX)
  1129.             {
  1130.                 leftX = (*segList)->v1->x;
  1131.             }
  1132.             if((*segList)->v1->x > rightX)
  1133.             {
  1134.                 rightX = (*segList)->v1->x;
  1135.             }
  1136.             if((*segList)->v1->y < bottomY)
  1137.             {
  1138.                 bottomY = (*segList)->v1->y;
  1139.             }
  1140.             if((*segList)->v1->y > topY)
  1141.             {
  1142.                 topY = (*segList)->v1->y;
  1143.             }
  1144.         }
  1145.         area = ((rightX>>FRACBITS)-(leftX>>FRACBITS))*
  1146.             ((topY>>FRACBITS)-(bottomY>>FRACBITS));
  1147.  
  1148. //    fprintf(stdaux, "Area of Polyobj[%d]: %d\n", polyobjs[i].tag, area);
  1149. //    fprintf(stdaux, "\t[%d]\n[%d]\t\t[%d]\n\t[%d]\n", topY>>FRACBITS, 
  1150. //            leftX>>FRACBITS,
  1151. //        rightX>>FRACBITS, bottomY>>FRACBITS);
  1152.     }
  1153. }
  1154.  
  1155. //==========================================================================
  1156. //
  1157. // IterFindPolySegs
  1158. //
  1159. //              Passing NULL for segList will cause IterFindPolySegs to
  1160. //      count the number of segs in the polyobj
  1161. //==========================================================================
  1162.  
  1163. static void IterFindPolySegs(int x, int y, seg_t **segList)
  1164. {
  1165.     int i;
  1166.  
  1167.     if(x == PolyStartX && y == PolyStartY)
  1168.     {
  1169.         return;
  1170.     }
  1171.     for(i = 0; i < numsegs; i++)
  1172.     {
  1173.         if(segs[i].v1->x == x && segs[i].v1->y == y)
  1174.         {
  1175.             if(!segList)
  1176.             {
  1177.                 PolySegCount++;
  1178.             }
  1179.             else
  1180.             {
  1181.                 *segList++ = &segs[i];
  1182.             }
  1183.             IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, segList);
  1184.             return;
  1185.         }
  1186.     }
  1187.     I_Error("IterFindPolySegs:  Non-closed Polyobj located.\n");
  1188. }
  1189.  
  1190.  
  1191. //==========================================================================
  1192. //
  1193. // SpawnPolyobj
  1194. //
  1195. //==========================================================================
  1196.  
  1197. static void SpawnPolyobj(int index, int tag, boolean crush)
  1198. {
  1199.     int i;
  1200.     int j;
  1201.     int psIndex;
  1202.     int psIndexOld;
  1203.     seg_t *polySegList[PO_MAXPOLYSEGS];
  1204.  
  1205.     for(i = 0; i < numsegs; i++)
  1206.     {
  1207.         if(segs[i].linedef->special == PO_LINE_START &&
  1208.             segs[i].linedef->arg1 == tag)
  1209.         {
  1210.             if(polyobjs[index].segs)
  1211.             {
  1212.                 I_Error("SpawnPolyobj:  Polyobj %d already spawned.\n", tag);
  1213.             }
  1214.             segs[i].linedef->special = 0;
  1215.             segs[i].linedef->arg1 = 0;
  1216.             PolySegCount = 1;
  1217.             PolyStartX = segs[i].v1->x;
  1218.             PolyStartY = segs[i].v1->y;
  1219.             IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, NULL);
  1220.  
  1221.             polyobjs[index].numsegs = PolySegCount;
  1222.             polyobjs[index].segs = Z_Malloc(PolySegCount*sizeof(seg_t *),
  1223.                 PU_LEVEL, 0);
  1224.             *(polyobjs[index].segs) = &segs[i]; // insert the first seg
  1225.             IterFindPolySegs(segs[i].v2->x, segs[i].v2->y,
  1226.                 polyobjs[index].segs+1);
  1227.             polyobjs[index].crush = crush;
  1228.             polyobjs[index].tag = tag;
  1229.             polyobjs[index].seqType = segs[i].linedef->arg3;
  1230.             if(polyobjs[index].seqType < 0 
  1231.                 || polyobjs[index].seqType >= SEQTYPE_NUMSEQ)
  1232.             {
  1233.                 polyobjs[index].seqType = 0;
  1234.             }
  1235.             break;
  1236.         }
  1237.     }
  1238.     if(!polyobjs[index].segs)
  1239.     { // didn't find a polyobj through PO_LINE_START
  1240.         psIndex = 0;
  1241.         polyobjs[index].numsegs = 0;
  1242.         for(j = 1; j < PO_MAXPOLYSEGS; j++)
  1243.         {
  1244.             psIndexOld = psIndex;
  1245.             for (i = 0; i < numsegs; i++)
  1246.             {
  1247.                 if(segs[i].linedef->special == PO_LINE_EXPLICIT &&
  1248.                     segs[i].linedef->arg1 == tag)
  1249.                 {
  1250.                     if(!segs[i].linedef->arg2)
  1251.                     {
  1252.                         I_Error("SpawnPolyobj:  Explicit line missing order number (probably %d) in poly %d.\n",
  1253.                             j+1, tag);
  1254.                     }
  1255.                     if(segs[i].linedef->arg2 == j)
  1256.                     {
  1257.                         polySegList[psIndex] = &segs[i];
  1258.                         polyobjs[index].numsegs++;
  1259.                         psIndex++;
  1260.                         if(psIndex > PO_MAXPOLYSEGS)
  1261.                         {
  1262.                             I_Error("SpawnPolyobj:  psIndex > PO_MAXPOLYSEGS\n");
  1263.                         }
  1264.                     }
  1265.                 }
  1266.             }
  1267.             // Clear out any specials for these segs...we cannot clear them out
  1268.             //     in the above loop, since we aren't guaranteed one seg per
  1269.             //        linedef.
  1270.             for(i = 0; i < numsegs; i++)
  1271.             {
  1272.                 if(segs[i].linedef->special == PO_LINE_EXPLICIT &&
  1273.                     segs[i].linedef->arg1 == tag && segs[i].linedef->arg2 == j)
  1274.                 {
  1275.                     segs[i].linedef->special = 0;
  1276.                     segs[i].linedef->arg1 = 0;
  1277.                 }
  1278.             }
  1279.             if(psIndex == psIndexOld)
  1280.             { // Check if an explicit line order has been skipped
  1281.                 // A line has been skipped if there are any more explicit
  1282.                 // lines with the current tag value
  1283.                 for(i = 0; i < numsegs; i++)
  1284.                 {
  1285.                     if(segs[i].linedef->special == PO_LINE_EXPLICIT &&
  1286.                         segs[i].linedef->arg1 == tag)
  1287.                     {
  1288.                         I_Error("SpawnPolyobj:  Missing explicit line %d for poly %d\n",
  1289.                             j, tag);
  1290.                     }
  1291.                 }
  1292.             }
  1293.         }
  1294.         if(polyobjs[index].numsegs)
  1295.         {
  1296.             PolySegCount = polyobjs[index].numsegs; // PolySegCount used globally
  1297.             polyobjs[index].crush = crush;
  1298.             polyobjs[index].tag = tag;
  1299.             polyobjs[index].segs = Z_Malloc(polyobjs[index].numsegs
  1300.                 *sizeof(seg_t *), PU_LEVEL, 0);
  1301.             for(i = 0; i < polyobjs[index].numsegs; i++)
  1302.             {
  1303.                 polyobjs[index].segs[i] = polySegList[i];
  1304.             }
  1305.             polyobjs[index].seqType = (*polyobjs[index].segs)->linedef->arg4;
  1306.         }
  1307.         // Next, change the polyobjs first line to point to a mirror
  1308.         //        if it exists
  1309.         (*polyobjs[index].segs)->linedef->arg2 =
  1310.             (*polyobjs[index].segs)->linedef->arg3;
  1311.     }
  1312. }
  1313.  
  1314. //==========================================================================
  1315. //
  1316. // TranslateToStartSpot
  1317. //
  1318. //==========================================================================
  1319.  
  1320. static void TranslateToStartSpot(int tag, int originX, int originY)
  1321. {
  1322.     seg_t **tempSeg;
  1323.     seg_t **veryTempSeg;
  1324.     vertex_t *tempPt;
  1325.     subsector_t *sub;
  1326.     polyobj_t *po;
  1327.     int deltaX;
  1328.     int deltaY;
  1329.     vertex_t avg; // used to find a polyobj's center, and hence subsector
  1330.     int i;
  1331.  
  1332.     po = NULL;
  1333.     for(i = 0; i < po_NumPolyobjs; i++)
  1334.     {
  1335.         if(polyobjs[i].tag == tag)
  1336.         {
  1337.             po = &polyobjs[i];
  1338.             break;
  1339.         }
  1340.     }
  1341.     if(!po)
  1342.     { // didn't match the tag with a polyobj tag
  1343.         I_Error("TranslateToStartSpot:  Unable to match polyobj tag: %d\n",
  1344.             tag);
  1345.     }
  1346.     if(po->segs == NULL)
  1347.     {
  1348.         I_Error("TranslateToStartSpot:  Anchor point located without a StartSpot point: %d\n", tag);
  1349.     }
  1350.     po->originalPts = Z_Malloc(po->numsegs*sizeof(vertex_t), PU_LEVEL, 0);
  1351.     po->prevPts = Z_Malloc(po->numsegs*sizeof(vertex_t), PU_LEVEL, 0);
  1352.     deltaX = originX-po->startSpot.x;
  1353.     deltaY = originY-po->startSpot.y;
  1354.  
  1355.     tempSeg = po->segs;
  1356.     tempPt = po->originalPts;
  1357.     avg.x = 0;
  1358.     avg.y = 0;
  1359.  
  1360.     validcount++;
  1361.     for(i = 0; i < po->numsegs; i++, tempSeg++, tempPt++)
  1362.     {
  1363.         if((*tempSeg)->linedef->validcount != validcount)
  1364.         {
  1365.             (*tempSeg)->linedef->bbox[BOXTOP] -= deltaY;
  1366.             (*tempSeg)->linedef->bbox[BOXBOTTOM] -= deltaY;
  1367.             (*tempSeg)->linedef->bbox[BOXLEFT] -= deltaX;
  1368.             (*tempSeg)->linedef->bbox[BOXRIGHT] -= deltaX;
  1369.             (*tempSeg)->linedef->validcount = validcount;
  1370.         }
  1371.         for(veryTempSeg = po->segs; veryTempSeg != tempSeg; veryTempSeg++)
  1372.         {
  1373.             if((*veryTempSeg)->v1 == (*tempSeg)->v1)
  1374.             {
  1375.                 break;
  1376.             }
  1377.         }
  1378.         if(veryTempSeg == tempSeg)
  1379.         { // the point hasn't been translated, yet
  1380.             (*tempSeg)->v1->x -= deltaX;
  1381.             (*tempSeg)->v1->y -= deltaY;
  1382.         }
  1383.         avg.x += (*tempSeg)->v1->x>>FRACBITS;
  1384.         avg.y += (*tempSeg)->v1->y>>FRACBITS;
  1385.         // the original Pts are based off the startSpot Pt, and are
  1386.         // unique to each seg, not each linedef
  1387.         tempPt->x = (*tempSeg)->v1->x-po->startSpot.x;
  1388.         tempPt->y = (*tempSeg)->v1->y-po->startSpot.y;
  1389.     }
  1390.     avg.x /= po->numsegs;
  1391.     avg.y /= po->numsegs;
  1392.     sub = R_PointInSubsector(avg.x<<FRACBITS, avg.y<<FRACBITS);
  1393.     if(sub->poly != NULL)
  1394.     {
  1395.         I_Error("PO_TranslateToStartSpot:  Multiple polyobjs in a single subsector.\n");
  1396.     }
  1397.     sub->poly = po;
  1398. }
  1399.  
  1400. //==========================================================================
  1401. //
  1402. // PO_Init
  1403. //
  1404. //==========================================================================
  1405.  
  1406. void PO_Init(int lump)
  1407. {
  1408.     byte                    *data;
  1409.     int                             i;
  1410.     mapthing_t              *mt;
  1411.     int                             numthings;
  1412.     int polyIndex;
  1413.  
  1414.     polyobjs = Z_Malloc(po_NumPolyobjs*sizeof(polyobj_t), PU_LEVEL, 0);
  1415.     memset(polyobjs, 0, po_NumPolyobjs*sizeof(polyobj_t));
  1416.  
  1417.     data = W_CacheLumpNum(lump, PU_STATIC);
  1418.     numthings = W_LumpLength(lump)/sizeof(mapthing_t);
  1419.     mt = (mapthing_t *)data;
  1420.     polyIndex = 0; // index polyobj number
  1421.     // Find the startSpot points, and spawn each polyobj
  1422.     for (i = 0; i < numthings; i++, mt++)
  1423.     {
  1424.         mt->x = SHORT(mt->x);
  1425.         mt->y = SHORT(mt->y);
  1426.         mt->angle = SHORT(mt->angle);
  1427.         mt->type = SHORT(mt->type);
  1428.  
  1429.         // 3001 = no crush, 3002 = crushing
  1430.         if(mt->type == PO_SPAWN_TYPE || mt->type == PO_SPAWNCRUSH_TYPE)
  1431.         { // Polyobj StartSpot Pt.
  1432.             polyobjs[polyIndex].startSpot.x = mt->x<<FRACBITS;
  1433.             polyobjs[polyIndex].startSpot.y = mt->y<<FRACBITS;
  1434.             SpawnPolyobj(polyIndex, mt->angle, (mt->type == PO_SPAWNCRUSH_TYPE));
  1435.             polyIndex++;
  1436.         }
  1437.     }
  1438.     mt = (mapthing_t *)data;
  1439.     for (i = 0; i < numthings; i++, mt++)
  1440.     {
  1441.         mt->x = SHORT(mt->x);
  1442.         mt->y = SHORT(mt->y);
  1443.         mt->angle = SHORT(mt->angle);
  1444.         mt->type = SHORT(mt->type);
  1445.         if(mt->type == PO_ANCHOR_TYPE)
  1446.         { // Polyobj Anchor Pt.
  1447.             TranslateToStartSpot(mt->angle, mt->x<<FRACBITS, mt->y<<FRACBITS);
  1448.         }
  1449.     }
  1450.     Z_Free (data);
  1451.     // check for a startspot without an anchor point
  1452.     for(i = 0; i < po_NumPolyobjs; i++)
  1453.     {
  1454.         if(!polyobjs[i].originalPts)
  1455.         {
  1456.             I_Error("PO_Init:  StartSpot located without an Anchor point: %d\n",
  1457.                 polyobjs[i].tag);
  1458.         }
  1459.     }
  1460.     InitBlockMap();
  1461. }
  1462.  
  1463. //==========================================================================
  1464. //
  1465. // PO_Busy
  1466. //
  1467. //==========================================================================
  1468.  
  1469. boolean PO_Busy(int polyobj)
  1470. {
  1471.     polyobj_t *poly;
  1472.  
  1473.     poly = GetPolyobj(polyobj);
  1474.     if(!poly->specialdata)
  1475.     {
  1476.         return false;
  1477.     }
  1478.     else
  1479.     {
  1480.         return true;
  1481.     }
  1482. }
  1483.